#include "stdafx.h"
#include "GotoAddressDialog.h"
#include "resource.h"
#include <string>
#include <assert.h>

GotoAddressDialog::GotoAddressDialog(LONGLONG inFileLength)
{
	mFileLength = inFileLength;
}


bool GotoAddressDialog::DoModal(HINSTANCE inInstance, HWND inParentWindow)
{
	INT_PTR result = ::DialogBoxParam(inInstance, MAKEINTRESOURCE(IDD_DIALOG_GOTO),
		inParentWindow, &GotoAddressDialog::DialogProc,
		reinterpret_cast<LPARAM>(this));

	return (TRUE == result);
}

LONGLONG GotoAddressDialog::GetAddress() const
{
	return mAddress;
}

// ---- private -----

// static
LRESULT CALLBACK GotoAddressDialog::WindowProcForEditField(HWND hwndEdit,
	UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LONG_PTR param = ::GetWindowLongPtr(hwndEdit, GWLP_USERDATA);
	auto pThis = reinterpret_cast<GotoAddressDialog *>(param);
	assert(nullptr != pThis);

	LRESULT result = ::CallWindowProc(pThis->mDefaultProcedureForEditField,
		hwndEdit, uMsg, wParam, lParam);
	
	if (WM_CHAR == uMsg)
	{
		pThis->ValidateAddress();
	}

	return result;
}


// static 
INT_PTR CALLBACK GotoAddressDialog::DialogProc(HWND hwndDlg, UINT inMessage,
	WPARAM wParam, LPARAM lParam)
{
	INT_PTR result = FALSE;
	if (WM_INITDIALOG == inMessage)
	{
		HWND editField = ::GetDlgItem(hwndDlg, IDC_EDIT_GOTO);
		if (editField == (HWND)wParam)
		{
			result = true;
		}
		if (auto pThis = reinterpret_cast<GotoAddressDialog *>(lParam))
		{
			pThis->LinkToDilogWindow(hwndDlg);
		}
	}
	else if (WM_COMMAND == inMessage)
	{
		switch (LOWORD(wParam))
		{
		case IDOK:
			::EndDialog(hwndDlg, TRUE);
			break;
		case IDCANCEL:
			::EndDialog(hwndDlg, FALSE);
			break;
		}
	}
	return result;
}


void GotoAddressDialog::ValidateAddress()
{
	// the number of hex digits is twice the number of bytes
	static const int kMaxDigits = 2 * sizeof(mAddress);
	int n = ::GetWindowTextLengthA(mEditField);
	bool shouldEnable = (0 < n && n <= kMaxDigits);

	if (shouldEnable)
	{
		char text[kMaxDigits + 1];
		::GetWindowTextA(mEditField, text, sizeof(text));

		char* endPtr;
		mAddress = std::strtoll(text, &endPtr, 16);
		shouldEnable = (mAddress < mFileLength && &text[n] == endPtr);
	}
	::EnableWindow(mOkButton, shouldEnable);
}

void GotoAddressDialog::LinkToDilogWindow(HWND inDialogWindow)
{
	mEditField = ::GetDlgItem(inDialogWindow, IDC_EDIT_GOTO);
	mOkButton = ::GetDlgItem(inDialogWindow, IDOK);

	::SetWindowLongPtr(mEditField, GWLP_USERDATA,
		reinterpret_cast<LONG_PTR>(this));
	mDefaultProcedureForEditField = reinterpret_cast<WNDPROC>(
		::GetWindowLongPtr(mEditField, GWL_WNDPROC));
	::SetWindowLongPtr(mEditField, GWL_WNDPROC,
		reinterpret_cast<LONG_PTR>(&GotoAddressDialog::WindowProcForEditField));

	ValidateAddress();
}